<script>
import {
  GlCard,
  GlButton,
  GlDrawer,
  GlLoadingIcon,
  GlAlert,
  GlSprintf,
  GlLink,
  GlIcon,
  GlBadge,
} from '@gitlab/ui';
import SafeHtml from '~/vue_shared/directives/safe_html';
import { getContentWrapperHeight } from '~/lib/utils/dom_utils';
import { DRAWER_CONTAINER_CLASS } from '~/ci/pipeline_editor/components/job_assistant_drawer/constants';
import { s__ } from '~/locale';
import { getMarkdown } from '~/rest_api';
import { renderGFM } from '~/behaviors/markdown/render_gfm';
import aiResponseSubscription from 'ee/graphql_shared/subscriptions/ai_completion_response.subscription.graphql';
import aiActionMutation from 'ee/graphql_shared/mutations/ai_action.mutation.graphql';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_USER, TYPENAME_VULNERABILITY } from '~/graphql_shared/constants';
import { helpPagePath } from '~/helpers/help_page_helper';

export default {
  components: {
    GlCard,
    GlButton,
    GlDrawer,
    GlLoadingIcon,
    GlAlert,
    GlSprintf,
    GlLink,
    GlIcon,
    GlBadge,
  },
  directives: { SafeHtml },
  props: {
    vulnerability: { type: Object, required: true },
  },
  data() {
    return {
      isLoading: false,
      isDrawerOpen: false,
      markdown: '',
      hasError: false,
    };
  },
  apollo: {
    $subscribe: {
      aiCompletionResponse: {
        query: aiResponseSubscription,
        variables() {
          return {
            resourceId: this.vulnerabilityGraphqlId,
            userId: convertToGraphQLId(TYPENAME_USER, gon.current_user_id),
          };
        },
        async result({ data }) {
          // When we first subscribe, we will receive a null aiCompletionResponse. We do nothing in this case.
          const { errors = [], responseBody } = data.aiCompletionResponse || {};

          if (errors.length) {
            this.isLoading = false;
            this.showError(errors.join(' '));
          } else if (responseBody) {
            // Use the markdown REST API to format the text using GitLab's format.
            const markdownResponse = await getMarkdown({ text: responseBody, gfm: true });
            this.isLoading = false;
            this.markdown = markdownResponse.data.html;
            // Wait for the browser to render the markdown first. $nextTick doesn't work here because it's too fast.
            requestAnimationFrame(() => {
              // Use renderGFM() to add syntax highlighting to the markdown.
              renderGFM(this.$refs.markdown);
            });
          }
        },
      },
    },
  },
  computed: {
    headerHeight() {
      return getContentWrapperHeight(DRAWER_CONTAINER_CLASS);
    },
    vulnerabilityGraphqlId() {
      return convertToGraphQLId(TYPENAME_VULNERABILITY, this.vulnerability.id);
    },
  },
  methods: {
    getExplanation() {
      this.isDrawerOpen = true;
      this.isLoading = true;
      this.hasError = false;

      this.$apollo
        .mutate({
          mutation: aiActionMutation,
          variables: {
            input: {
              explainVulnerability: { resourceId: this.vulnerabilityGraphqlId },
            },
          },
        })
        .catch(this.showError);
    },
    closeDrawer() {
      this.isDrawerOpen = false;
    },
    showError() {
      this.isLoading = false;
      this.hasError = true;
    },
  },
  i18n: {
    cardTitle: s__('Vulnerability|Explain this vulnerability and how to mitigate it with AI'),
    cardText: s__(
      'Vulnerability|This is an experimental feature that uses AI to explain the vulnerability and provide recommendations. Use this feature with caution as we continue to iterate. Please provide your feedback and ideas in %{linkStart}this issue%{linkEnd}.',
    ),
    buttonText: s__('Vulnerability|Try it out'),
    drawerTitle: s__('Vulnerability|Explain this vulnerability'),
    drawerSubtitle: s__('Vulnerability|This response is generated by AI.'),
    experimentLabel: s__('Vulnerability|Experiment'),
    requestError: s__(
      'Vulnerability|There was an unexpected error. %{linkStart}Please try again%{linkEnd}.',
    ),
  },
  feedbackIssueHref: 'https://gitlab.com/gitlab-org/gitlab/-/issues/407295',
  experimentDocHref: helpPagePath('policy/alpha-beta-support', { anchor: 'experiment' }),
};
</script>

<template>
  <gl-card class="gl-banner-introduction gl-border-none!" body-class="gl-display-flex">
    <gl-icon name="information-o" class="gl-flex-shrink-0 gl-mr-5 gl-text-blue-600" />
    <div>
      <h5 class="gl-mb-3!">
        {{ $options.i18n.cardTitle }}
        <gl-badge variant="info" size="sm" class="gl-ml-2" :href="$options.experimentDocHref">
          {{ $options.i18n.experimentLabel }}
        </gl-badge>
      </h5>
      <p class="gl-mb-3!">
        <gl-sprintf :message="$options.i18n.cardText">
          <template #link="{ content }">
            <gl-link :href="$options.feedbackIssueHref" target="_blank">{{ content }}</gl-link>
          </template>
        </gl-sprintf>
      </p>
      <gl-button variant="confirm" :disabled="isDrawerOpen" @click="getExplanation">
        {{ $options.i18n.buttonText }}
      </gl-button>
    </div>

    <gl-drawer
      :open="isDrawerOpen"
      :header-height="headerHeight"
      header-sticky
      class="gl-reset-line-height"
      @close="closeDrawer"
    >
      <template #title>
        <h1 class="gl-mb-2! gl-pb-0! gl-border-none!">{{ $options.i18n.drawerTitle }}</h1>
      </template>
      <template #header>
        <h4 class="gl-mb-0! gl-mt-3!">{{ $options.i18n.drawerSubtitle }}</h4>
      </template>

      <gl-loading-icon v-if="isLoading" size="lg" class="gl-mt-6!" />
      <div v-else-if="hasError">
        <gl-alert variant="danger" :dismissible="false">
          <gl-sprintf :message="$options.i18n.requestError">
            <template #link="{ content }">
              <gl-button variant="link" @click="getExplanation">{{ content }}</gl-button>
            </template>
          </gl-sprintf>
        </gl-alert>
      </div>
      <div v-else ref="markdown" v-safe-html="markdown"></div>
    </gl-drawer>
  </gl-card>
</template>
